package com.yifeng.repo.apm.endpoint.logging.logback;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.ThrowableProxy;
import ch.qos.logback.core.AppenderBase;
import com.alibaba.fastjson.JSON;
import com.yifeng.repo.apm.endpoint.console.api.model.LogConfTypeEnum;
import com.yifeng.repo.apm.endpoint.sender.LogSender;
import com.yifeng.repo.apm.endpoint.sender.LogSenderManager;
import com.yifeng.repo.apm.endpoint.utils.BaseUtil;
import next.fire.spinus.logx.api.model.LevelEnum;
import next.fire.spinus.logx.api.model.LogData;
import next.fire.spinus.logx.utils.env.HostManager;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by daibing on 2021/2/19.
 */
public class TraceLogbackAppender extends AppenderBase<ILoggingEvent> {
    private String appId;
    private String appStage;
    private String hostName;

    @Override
    public void start() {
        super.start();
        HostManager util = HostManager.get();
        appId = util.getEnvSetting("app.id", "app_id");
        appStage = util.getEnvSetting("app.stage", "app_stage");
        hostName = util.getHostName();
        LogSenderManager.startupLogSender();
    }

    @Override
    public void stop() {
        LogSenderManager.shutdownSender();
        super.stop();
    }

    @Override
    protected void append(ILoggingEvent event) {
        LogSender logSender = LogSenderManager.getLogSender(true);
        if (!logSender.isLogEnabled(LogConfTypeEnum.CLOUD)) {
            return;
        }
        if (!logSender.matched(event.getLoggerName(), LevelEnum.get(event.getLevel().toString()))) {
            return;
        }
        LogData logData = new LogData();
        logData.setAppId(this.appId);
        logData.setStage(this.appStage);
        logData.setLevel(LevelEnum.get(event.getLevel().toString()));
        logData.setLogTime(event.getTimeStamp());
        logData.setTraceId(BaseUtil.getTraceId());
        logData.setFrontendId(BaseUtil.getFrontendId());
        logData.setHost(this.hostName);
        logData.setThread(event.getThreadName());
        logData.setLocation(event.getLoggerName());
        String message = event.getFormattedMessage();
        if (BaseUtil.isNotBlank(message)) {
            logData.setMessage(message);
        }
        if (event.getThrowableProxy() != null) {
            Throwable throwable = ((ThrowableProxy) event.getThrowableProxy()).getThrowable();
            logData.setThrowable(this.render(throwable));
        }
        logSender.send(logData);
    }

    private String render(Throwable t) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        try {
            t.printStackTrace(pw);
        } catch (RuntimeException e) {
            // ignore.
        }
        pw.flush();
        LineNumberReader reader = new LineNumberReader(new StringReader(sw.toString()));
        List<String> lines = new ArrayList<>();
        try {
            String line = reader.readLine();
            while (line != null) {
                lines.add(line);
                line = reader.readLine();
            }
        } catch (IOException e) {
            if (e instanceof InterruptedIOException) {
                Thread.currentThread().interrupt();
            }
            lines.add(e.toString());
        }
        return JSON.toJSONString(lines);
    }
}
